/* 聊天会话表的ODB映射操作 */

#include "mysql.hpp"
#include "chat_session.hxx"
#include "chat_session-odb.hxx"
#include "chat_session_member.hxx"
#include "chat_session_member-odb.hxx"

namespace ChatSystem
{
    //聊天会话表ODB操作
    class ChatSessionTable
    {
    public:
        using ptr = std::shared_ptr<ChatSessionTable>;

        ChatSessionTable() = delete;
        ChatSessionTable(const std::shared_ptr<odb::core::database>& db)
        :_db(db)
        {}
        ~ChatSessionTable(){}

        //新增聊天会话信息
        bool insert(ChatSystem::ChatSession& chat_session)
        {
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //获取对象开启事务
                odb::transaction trans(_db->begin());
                _db->persist(chat_session);
                //提交事务
                trans.commit();
            }
            catch(const std::exception& e)
            {
                LOG_ERROR("新增 {} 聊天会话时失败, {}!", chat_session.chat_session_id(), e.what());
                return false;
            }
            return true;   
        }

        //删除聊天会话表中的信息---在删除聊天会话表中的会话表中的会话的时候，按理来说是要将会话成员表中会话对应的成员信息都删除掉的，
        //即会话表和会话成员表之间是存在外键约束的，在删除会话表中的会话的时候应该一起删除会话成员表中对应的成员信息
        bool remove(const std::string& chat_session_id)
        {
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //获取对象开启事务
                odb::transaction trans(_db->begin());
                //1. 先查询
                typedef odb::query<ChatSession> query;
                typedef odb::result<ChatSession> result;
                //_db->erase接口是通过对象来删除，_db->erase_query是通过过滤条件来删除；
                _db->erase_query<ChatSession>(query::chat_session_id == chat_session_id);
                //chat_session表和chat_session_member表之间是存在外键约束的，删除会话表中的会话时，也应该将会话成员表中的对应数据一起删除掉；
                typedef odb::query<ChatSessionMember> member_query;
                _db->erase_query<ChatSessionMember>(member_query::chat_session_id == chat_session_id);
                //提交事务
                trans.commit();
            }
            catch(const std::exception& e)
            {
                LOG_ERROR("通过聊天会话ID删除聊天会话 {} 时失败, {}!", chat_session_id, e.what());
                return false;
            }
            return true;  
        }

        //删除聊天会话表中的信息---通过 user_id 和 peer_id来删除
        bool remove(const std::string& user_id, const std::string& peer_id)
        {
            std::string chat_session_id;
            //单聊会话的删除 --- 根据单聊会话的两个成员删除
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //获取对象开启事务
                odb::transaction trans(_db->begin());
                //1. 先查询
                typedef odb::query<SingleChatSession> query;
                //_db->erase接口是通过对象来删除，_db->erase_query是通过过滤条件来删除；
                auto res = _db->query_one<SingleChatSession>(query::csm1::user_id == user_id 
                    && query::csm2::user_id == peer_id 
                    && query::css::chat_session_type == ChatSessionType::SINGLE);
                if(res == nullptr)
                {
                    LOG_ERROR("查询不到 {}:{} 对应的聊天会话！", user_id, peer_id);
                }
                chat_session_id = res->chat_session_id;

                typedef odb::query<ChatSession> session_query;
                //_db->erase接口是通过对象来删除，_db->erase_query是通过过滤条件来删除；
                _db->erase_query<ChatSession>(session_query::chat_session_id == chat_session_id);
                //chat_session表和chat_session_member表之间是存在外键约束的，删除会话表中的会话时，也应该将会话成员表中的对应数据一起删除掉；
                typedef odb::query<ChatSessionMember> member_query;
                _db->erase_query<ChatSessionMember>(member_query::chat_session_id == chat_session_id);
                //提交事务
                trans.commit();
            }
            catch(const std::exception& e)
            {
                LOG_ERROR("通过好友关系删除聊天会话 {} 时失败, {}!", chat_session_id, e.what());
                return false;
            }
            return true;  
        }

        //通过聊天会话ID，获取聊天会话的详细信息
        std::shared_ptr<ChatSession> select(const std::string& chat_session_id)
        {
            std::shared_ptr<ChatSession> res;
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //3. 获取事务操作对象，开启事务
                odb::transaction trans(_db->begin());
                //4. 数据操作
                typedef odb::query<ChatSession> query;
                typedef odb::result<ChatSession> result;
                res = std::shared_ptr<ChatSession>(_db->query_one<ChatSession>(query::chat_session_id == chat_session_id));
                //5. 提交事务
                trans.commit();
            }
            catch(std::exception& e)
            {
                LOG_ERROR("获取聊天会话 {} 的详细信息时失败, {}", chat_session_id, e.what());
            }
            return res;
        }

        //通过用户ID获取所有单聊会话
        std::vector<SingleChatSession> singleChatSession(const std::string& user_id)
        {
            std::vector<SingleChatSession> res;
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //3. 获取事务操作对象，开启事务
                odb::transaction trans(_db->begin());
                //4. 数据操作
                typedef odb::query<SingleChatSession> query;
                typedef odb::result<SingleChatSession> result;
                result r(_db->query<SingleChatSession>(query::css::chat_session_type == ChatSessionType::SINGLE 
                    && query::csm1::user_id == user_id 
                    && query::csm2::user_id != query::csm1::user_id));
                for(auto it = r.begin(); it != r.end(); ++it)
                {
                    res.push_back(*it);
                }
                //5. 提交事务
                trans.commit();
            }
            catch(std::exception& e)
            {
                LOG_ERROR("获取指定用户 {} 的所有单聊会话失败, {}", user_id, e.what());
            }
            return res;
        }
    
        //通过用户ID获取所有群聊会话
        std::vector<GroupChatSession> groupChatSession(const std::string& user_id)
        {
            std::vector<GroupChatSession> res;
            //数据的所有操作都会有可能导致程序的崩溃，所以需要捕捉异常防止程序的退出；
            try
            {
                //3. 获取事务操作对象，开启事务
                odb::transaction trans(_db->begin());
                //4. 数据操作
                typedef odb::query<GroupChatSession> query;
                typedef odb::result<GroupChatSession> result;
                result r(_db->query<GroupChatSession>(query::css::chat_session_type == ChatSessionType::GROUP 
                    && query::csm::user_id == user_id));
                for(auto it = r.begin(); it != r.end(); ++it)
                {
                    res.push_back(*it);
                }
                //5. 提交事务
                trans.commit();
            }
            catch(std::exception& e)
            {
                LOG_ERROR("获取指定用户 {} 的所有单聊会话失败, {}", user_id, e.what());
            }
            return res;
        }


    private:
        std::shared_ptr<odb::core::database> _db;
    };
}